
#include "Interpreter.h"
#include "NodeAction.h"
#include "NodeAnd.h"
#include "NodeDirection.h"
#include "NodeDistance.h"
#include "NodeSentence.h"
#include <stack>

using namespace npInterpreter;
using namespace std;


Interpreter::Interpreter() // class inheritance
{
    //To initialize data member;
    this->root = nullptr;
}

Interpreter::~Interpreter()
{
    //To delete dynamic data member
    delete this->root;
}

Interpreter::Interpreter(const Interpreter& cpy) // class inheritance
{
    //To copy data member
    this->root = cpy.root->clone();
}

Interpreter& Interpreter::operator=(const Interpreter& asn)
{
    if (this == &asn)
    {
        return *this;
    }
    else
    {
        //To invoke base class operator=
        
        //To assign data member, note to delete dynamic member if exists.
        delete this->root;
        this->root = asn.root->clone();

        return *this;
    }
}

Interpreter::Interpreter(Interpreter&& mov) noexcept // class inheritance
{
    //to move data
    this->root = mov.root;
    mov.root = nullptr;
}

Interpreter& Interpreter::operator=(Interpreter&& mva) noexcept
{
    if (this == &mva)
    {
        return *this;
    }
    else
    {
        //to inform base class to move data
        
        // to move data
        delete this->root;
        this->root = mva.root;
        mva.root = nullptr;

        return *this;
    }
}

Interpreter* Interpreter::clone() const
{
    //return new
    return new Interpreter(*this);
}

//other constructors

//public methods
void Interpreter::handler(const string& instructions) throw()
{
    stack<Node*> cmdTree;
    vector<string> words;
    this->split(words, instructions, " ", true);
    for (size_t i = 0; i < words.size(); i++)
    {
        if (words[i] == "and")
        {
            Node* left = cmdTree.top();
            cmdTree.pop();
            Node* direction = new NodeDirection(words[++i]);
            Node* action = new NodeAction(words[++i]);
            Node* distance = new NodeDistance(words[++i]);
            Node* right = new NodeSentence(direction, action, distance);
            cmdTree.push(new NodeAnd(left, right));
        }
        else
        {
            i--;
            Node* direction = new NodeDirection(words[++i]);
            Node* action = new NodeAction(words[++i]);
            Node* distance = new NodeDistance(words[++i]);
            cmdTree.push(new NodeSentence(direction, action, distance));
        }
    }
    delete this->root;
    this->root = cmdTree.top();
    cmdTree.pop();
}

string Interpreter::output() throw()
{
    return this->root->interpret();
}

//protected methods

//private methods
vector<string>& Interpreter::split(vector<string>& results, const string& content, const string& separator, bool removeEmpty)
{
    vector<string>().swap(results);
    size_t s = 0;
    size_t t = 0;
    while ((t = content.find(separator, s)) != string::npos)
    {
        results.push_back(content.substr(s, t - s));
        s = t + separator.length();
    }
    results.push_back(content.substr(s, content.length()));

    if (removeEmpty)
    {
        vector<string>::iterator it = results.begin();
        while (it != results.end())
        {
            if (it->empty())
            {
                it = results.erase(it);
            }
            else
            {
                it++;
            }
        }
    }

    return results;
}

//others
